1
//--------------------------------------------------------------------------
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 //--------------------------------------------------------------------------
10 using System
.Collections
.Generic
;
11 using System
.Threading
;
12 using System
.Threading
.Tasks
;
14 namespace Microsoft
.ParallelComputingPlatform
.ParallelExtensions
.Samples
16 internal sealed class RayTracer
18 private int screenWidth
;
19 private int screenHeight
;
20 private const int MaxDepth
= 5;
22 public RayTracer(int screenWidth
, int screenHeight
)
24 this.screenWidth
= screenWidth
;
25 this.screenHeight
= screenHeight
;
28 internal void RenderSequential(Scene scene
, Int32
[] rgb
)
30 for (int y
= 0; y
< screenHeight
; y
++)
32 int stride
= y
* screenWidth
;
33 Camera camera
= scene
.Camera
;
34 for (int x
= 0; x
< screenWidth
; x
++)
36 Color color
= TraceRay(new Ray(camera
.Pos
, GetPoint(x
, y
, camera
)), scene
, 0);
37 rgb
[x
+ stride
] = color
.ToInt32();
42 internal void RenderParallel(Scene scene
, Int32
[] rgb
, ParallelOptions options
)
44 Parallel
.For(0, screenHeight
, options
, y
=>
46 int stride
= y
* screenWidth
;
47 Camera camera
= scene
.Camera
;
48 for (int x
= 0; x
< screenWidth
; x
++)
50 Color color
= TraceRay(new Ray(camera
.Pos
, GetPoint(x
, y
, camera
)), scene
, 0);
51 rgb
[x
+ stride
] = color
.ToInt32();
56 internal void RenderParallelShowingThreads(Scene scene
, Int32
[] rgb
, ParallelOptions options
)
59 Parallel
.For
<double>(0, screenHeight
, options
, () => GetHueShift(Interlocked
.Increment(ref id
)), (y
, state
, hue
) =>
61 int stride
= y
* screenWidth
;
62 Camera camera
= scene
.Camera
;
63 for (int x
= 0; x
< screenWidth
; x
++)
65 Color color
= TraceRay(new Ray(camera
.Pos
, GetPoint(x
, y
, camera
)), scene
, 0);
67 rgb
[x
+ stride
] = color
.ToInt32();
71 hue
=> Interlocked
.Decrement(ref id
));
74 private Dictionary
<int, double> _numToHueShiftLookup
= new Dictionary
<int, double>();
75 private Random _rand
= new Random();
77 private double GetHueShift(int id
)
80 lock (_numToHueShiftLookup
)
82 if (!_numToHueShiftLookup
.TryGetValue(id
, out shift
))
84 shift
= _rand
.NextDouble();
85 _numToHueShiftLookup
.Add(id
, shift
);
91 internal readonly Scene DefaultScene
= CreateDefaultScene();
93 static Scene
CreateDefaultScene()
95 SceneObject
[] things
= {
96 new Sphere( new Vector(-0.5,1,1.5), 0.5, Surfaces
.MatteShiny
),
97 new Sphere( new Vector(0,1,-0.25), 1, Surfaces
.Shiny
),
98 new Plane( new Vector(0,1,0), 0, Surfaces
.CheckerBoard
)
101 new Light(new Vector(-2,2.5,0),new Color(.5,.45,.41)),
102 new Light(new Vector(2,4.5,2), new Color(.99,.95,.8))
104 Camera camera
= Camera
.Create(new Vector(2.75, 2, 3.75), new Vector(-0.6, .5, 0));
106 return new Scene(things
, lights
, camera
);
110 private ISect
MinIntersection(Ray ray
, Scene scene
)
112 ISect min
= ISect
.Null
;
113 foreach (SceneObject obj
in scene
.Things
)
115 ISect isect
= obj
.Intersect(ray
);
116 if (!ISect
.IsNull(isect
))
118 if (ISect
.IsNull(min
) || min
.Dist
> isect
.Dist
)
127 private double TestRay(Ray ray
, Scene scene
)
129 ISect isect
= MinIntersection(ray
, scene
);
130 if (ISect
.IsNull(isect
))
135 private Color
TraceRay(Ray ray
, Scene scene
, int depth
)
137 ISect isect
= MinIntersection(ray
, scene
);
138 if (ISect
.IsNull(isect
))
139 return Color
.Background
;
140 return Shade(isect
, scene
, depth
);
143 private Color
GetNaturalColor(SceneObject thing
, Vector pos
, Vector norm
, Vector rd
, Scene scene
)
145 Color ret
= new Color(0, 0, 0);
146 foreach (Light light
in scene
.Lights
)
148 Vector ldis
= Vector
.Minus(light
.Pos
, pos
);
149 Vector livec
= Vector
.Norm(ldis
);
150 double neatIsect
= TestRay(new Ray(pos
, livec
), scene
);
151 bool isInShadow
= !((neatIsect
> Vector
.Mag(ldis
)) || (neatIsect
== 0));
154 double illum
= Vector
.Dot(livec
, norm
);
155 Color lcolor
= illum
> 0 ? Color
.Times(illum
, light
.Color
) : new Color(0, 0, 0);
156 double specular
= Vector
.Dot(livec
, Vector
.Norm(rd
));
157 Color scolor
= specular
> 0 ? Color
.Times(Math
.Pow(specular
, thing
.Surface
.Roughness
), light
.Color
) : new Color(0, 0, 0);
158 ret
= Color
.Plus(ret
, Color
.Plus(Color
.Times(thing
.Surface
.Diffuse(pos
), lcolor
),
159 Color
.Times(thing
.Surface
.Specular(pos
), scolor
)));
165 private Color
GetReflectionColor(SceneObject thing
, Vector pos
, Vector norm
, Vector rd
, Scene scene
, int depth
)
167 return Color
.Times(thing
.Surface
.Reflect(pos
), TraceRay(new Ray(pos
, rd
), scene
, depth
+ 1));
170 private Color
Shade(ISect isect
, Scene scene
, int depth
)
172 Vector d
= isect
.Ray
.Dir
;
173 Vector pos
= Vector
.Plus(Vector
.Times(isect
.Dist
, isect
.Ray
.Dir
), isect
.Ray
.Start
);
174 Vector normal
= isect
.Thing
.Normal(pos
);
175 Vector reflectDir
= Vector
.Minus(d
, Vector
.Times(2 * Vector
.Dot(normal
, d
), normal
));
176 Color ret
= Color
.DefaultColor
;
177 ret
= Color
.Plus(ret
, GetNaturalColor(isect
.Thing
, pos
, normal
, reflectDir
, scene
));
178 if (depth
>= MaxDepth
)
180 return Color
.Plus(ret
, new Color(.5, .5, .5));
182 return Color
.Plus(ret
, GetReflectionColor(isect
.Thing
, Vector
.Plus(pos
, Vector
.Times(.001, reflectDir
)), normal
, reflectDir
, scene
, depth
));
185 private double RecenterX(double x
)
187 return (x
- (screenWidth
/ 2.0)) / (2.0 * screenWidth
);
189 private double RecenterY(double y
)
191 return -(y
- (screenHeight
/ 2.0)) / (2.0 * screenHeight
);
194 private Vector
GetPoint(double x
, double y
, Camera camera
)
196 return Vector
.Norm(Vector
.Plus(camera
.Forward
, Vector
.Plus(Vector
.Times(RecenterX(x
), camera
.Right
),
197 Vector
.Times(RecenterY(y
), camera
.Up
))));